﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Net;
using System.IO;

namespace DownloadApi.Net
{
    class DownloadWorker : BackgroundWorker
    {
        #region Private members
        // id for this worker
        private int _WorkerId = 0;
        private int _JobId = -1;
        #endregion

        #region Properties
        public int WorkerId
        {
            get { return _WorkerId; }
            set { _WorkerId = value; }
        }
        public int JobId
        {
            get { return _JobId; }
            set { _JobId = value; }
        }
        #endregion

        public event EventHandler Complete;
        public event EventHandler Cancelled;
        
        /// <summary>
        /// UserState for Progress Updates
        /// </summary>
        public class ProgressUserState
        {
            private int _JobId;
            public int JobId
            {
                get { return _JobId; }
                set { _JobId = value; }
            }

            private Int64 _BytesRead;
            public Int64 BytesRead
            {
                get { return _BytesRead; }
                set { _BytesRead = value; }
            }
            private Int64 _TotalBytes;
            public Int64 TotalBytes
            {
                get { return _TotalBytes; }
                set { _TotalBytes = value; }
            }

        }


        #region [Constructor]
        /// <summary>
        /// Create worker with id
        /// </summary>
        /// <param name="workerid"></param>
        public DownloadWorker()
        {
            // this._WorkerId = workerid;
            this.WorkerReportsProgress = true;
            this.WorkerSupportsCancellation = true;
            this.DoWork += DoWorkNow;
            // this.ProgressChanged += WorkerProgressChanged;
            // this.RunWorkerCompleted += WorkerCompleted;
        }

        public DownloadWorker(int idxWorker) : this()
        {
            _WorkerId = idxWorker;
        }
        #endregion

        #region [Methods]
        /// <summary>
        /// Start This Download Process
        /// </summary>
        /// <param name="url"></param>
        /// <param name="path"></param>
        /// <param name="startPoint"></param>
        public void StartDownload(String url, String path, Int32 startPoint)
        {
            List<Object> arguments = new List<Object>();
            arguments.Add(url);
            arguments.Add(path);
            arguments.Add(startPoint);
            this.RunWorkerAsync(arguments);
        }
          
        private void DoWorkNow(Object sender, DoWorkEventArgs e)
        {
            List<Object> arguments = (List<Object>)e.Argument;
            HttpWebRequest req = null;
            HttpWebResponse res = null;
            Stream resStream = null;
            Stream localStream = null;
            try
            {
                for (int i = 0; i < arguments.Count;i++ )
                {
                    Console.WriteLine((string)arguments[i].ToString());
                }
                

                req = (HttpWebRequest)WebRequest.Create((String)arguments[0]);
                req.ContentType = "Application";
                req.AddRange((Int32)arguments[2]);
                req.Credentials = CredentialCache.DefaultCredentials;
                res = (HttpWebResponse)req.GetResponse();
                Int64 fileSize = res.ContentLength;
                resStream = res.GetResponseStream();

                if ((Int32)arguments[2] == 0)
                    localStream = new FileStream((String)arguments[1], FileMode.Create, FileAccess.Write, FileShare.None);
                else
                    localStream = new FileStream((String)arguments[1], FileMode.Append, FileAccess.Write, FileShare.None);

                int bytesSize = 0;
                byte[] downBuffer = new byte[2048];
                while ((bytesSize = resStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
                {
                    localStream.Write(downBuffer, 0, bytesSize);

                     // Create an object to report the status via UserState                     
                     ProgressUserState prgState = new ProgressUserState();
                     prgState.BytesRead  = localStream.Length;
                     prgState.TotalBytes = fileSize + (Int32)arguments[2];

                     // call the progress change event to update u.i, pass progress 1-100, and userstate
                     this.ReportProgress(Convert.ToInt32((localStream.Length * 100) / fileSize + (Int32)arguments[2]), prgState);

                    if (this.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }
                }
            }
            catch { throw; }
            finally
            {
                if (null != req)
                    req = null;
                if (null != res)
                    res.Close();
                if (null != resStream)
                    resStream.Close();
                if (null != localStream)
                    localStream.Close();
            }
        }
        /*
        private void WorkerProgressChanged(Object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            ProgressUserState prgUserState = (ProgressUserState)e.UserState;


            EventHandler<ProgressChangedEventArgs> copy = ProgressChanged2;
            if (null != copy)
                copy(this, new ProgressChangedEventArgs(progress, CurrentStatus[0], CurrentStatus[1]));

        }

        private void WorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
        {
            if (null != e.Error)
                throw new Exception("Operation cancelled!", e.Error);
            if (e.Cancelled)
                // OnCancelled();
                EventHandler copy = Cancelled;
                if (null != copy) copy(this, EventArgs.Empty);

            else
                EventHandler copy = Complete;
                if (null != copy) copy(this, EventArgs.Empty);

                
                // OnComplete();
        }
        */
        #endregion


    }
}